//
//  ZMWaterFallLayout.m
//  ZMKitDemo
//
//  Created by zm on 2018/6/22.
//  Copyright © 2018年 zm. All rights reserved.
//

#import "ZMWaterFallLayout.h"


static const CGFloat ZMWaterFallColumnCount = 3; //列数
static const CGFloat ZMWaterFallRowMargin = 10; //行间距
static const CGFloat ZMWaterFallColumnMargin = 10;//列间距
static const UIEdgeInsets ZMWaterFallEdgeInsets = {10, 10, 10, 10};//边缘间距

@interface ZMWaterFallLayout ()
{
    struct {//记录代理是否响应选择子
        BOOL didRespondColumnCount : 1;
        BOOL didRespondColumnMargin : 1;
        BOOL didRespondRowMargin : 1;
        BOOL didRespondEdgeInsets : 1;
    } _delegateFlags;
}

//cell的布局属性数组
@property (nonatomic, strong) NSMutableArray *attrs;
//每列的高度数组
@property (nonatomic, strong) NSMutableArray *columnHeights;
//最大的Y值
@property (nonatomic, assign) CGFloat maxY;

@end

@implementation ZMWaterFallLayout

#pragma mark - LazyLoad

- (NSMutableArray *)attrs {
    if (!_attrs) {
        _attrs = [NSMutableArray array];
    }
    return _attrs;
}

- (NSMutableArray *)columnHeights {
    if (!_columnHeights) {
        _columnHeights = [NSMutableArray array];
    }
    return _columnHeights;
}

#pragma mark - Layout
/**重写prepareLayout*/
- (void)prepareLayout {
    [super prepareLayout];
    
    //初始化列最大高度数组
    [self setupColumnHeights];
    //初始化item布局属性数组
    [self setupAttrs];
    //设置代理方法标志
    [self setupDelegateFlags];
    //计算最大的Y值
    self.maxY = [self caculateMaxY];
    
}

/**重写layoutAttributesForItemAtIndexPath*/
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    //计算item的x,y,width,height
    CGFloat collectionViewWidth = self.collectionView.frame.size.width;
    CGFloat width = (collectionViewWidth - [self edgeInsets].left - [self edgeInsets].right - ([self columnCount] - 1) * [self columnMargin]) / [self columnCount];
    
    //计算当前item应该摆在第几列，计算哪一列高度最短
    __block NSUInteger minColumn = 0;
    __block CGFloat minHeight = MAXFLOAT;
    [self.columnHeights enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSNumber *heightNumber = (NSNumber *)obj;
        if (minHeight > [heightNumber doubleValue]) {
            minHeight = [heightNumber doubleValue];
            minColumn = idx;
        }
    }];
    
    CGFloat x = [self edgeInsets].left + minColumn * ([self columnMargin] + width);
    CGFloat y = minHeight + [self rowMargin];
    
    CGFloat height = [self.delegate waterFallLayout:self heightForItemAtIndex:indexPath.row width:width];
    
    attribute.frame = CGRectMake(x, y, width, height);
    //更新数组中的最短列的高度
    self.columnHeights[minColumn] = @(y + height);
    
    return attribute;
}

- (CGFloat)caculateMaxY {
    __block CGFloat max_y = 0;
    [self.columnHeights enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSNumber *heightNumber = (NSNumber *)obj;
        if ([heightNumber doubleValue] > max_y) {
            max_y = [heightNumber doubleValue];
        }
    }];
    return max_y;
}

#pragma mark - Setup Methods
- (void)setupColumnHeights {
    [self.columnHeights removeAllObjects];
    
    //初始化列高度
    for (int i = 0; i < [self columnCount]; i ++) {
        [self.columnHeights addObject:@([self edgeInsets].top)];
    }
}

- (void)setupAttrs {
    [self.attrs removeAllObjects];
    
    NSUInteger count = [self.collectionView numberOfItemsInSection:0];
    for (int i = 0; i < count; i ++) {
        @autoreleasepool {
            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
            UICollectionViewLayoutAttributes *attr = [self layoutAttributesForItemAtIndexPath:indexPath];
            [self.attrs addObject:attr];
        }
    }
}

- (void)setupDelegateFlags {
    _delegateFlags.didRespondColumnCount = (self.delegate && [self.delegate respondsToSelector:@selector(columnCountOfWaterFallLayout:)]);
    
    _delegateFlags.didRespondRowMargin = (self.delegate && [self.delegate respondsToSelector:@selector(rowMarginOfWaterFallLayout:)]);

    _delegateFlags.didRespondColumnMargin = (self.delegate && [self.delegate respondsToSelector:@selector(columnMarginOfWaterFallLayout:)]);

    _delegateFlags.didRespondEdgeInsets = (self.delegate && [self.delegate respondsToSelector:@selector(edgeInsetsOfWaterFallLayout:)]);

}



#pragma mark - Delegate Methods
- (NSUInteger)columnCount {
    return  _delegateFlags.didRespondColumnCount ? [self.delegate columnCountOfWaterFallLayout:self] : ZMWaterFallColumnCount;
}

- (CGFloat)rowMargin {
    return _delegateFlags.didRespondRowMargin ? [self.delegate rowMarginOfWaterFallLayout:self] : ZMWaterFallRowMargin;
}

- (CGFloat)columnMargin {
    return _delegateFlags.didRespondColumnMargin ? [self.delegate columnMarginOfWaterFallLayout:self] : ZMWaterFallColumnMargin;
}

- (UIEdgeInsets)edgeInsets {
    return _delegateFlags.didRespondEdgeInsets ? [self.delegate edgeInsetsOfWaterFallLayout:self] : ZMWaterFallEdgeInsets;
}

@end
